Design Patterns - Strategy Pattern

Strategy-Image

Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from the clients that use it.

   
Intent Enables you to use different business rules or algorithms depending on the context in which they occur
Problem The selection of an algorithm that needs to be applied depends on the client making the request or the data being acted on.
Solution Separate the selection of algorithm from the implementation of the algorithm. Allows for the selection to be made based upon context.
Participants and Collaborators Strategy declares an interface common to all supported algorithms, and specifies how the different algorithms are used. Concrete Strategy implements these different algorithms using Strategy interface. Context uses a specific Concrete Strategy with a reference of the type Strategy
Consequences The Strategy pattern defines a family of algorithms. Switch or Conditional can be eliminated

Strategy-pattern-UML

Example

Strategy-pattern-UML

package com.art.designpatterns.strategy;
import com.google.common.collect.Lists;
import java.util.List;
public class StrategyDemo {
public static void main(String[] args) {
PromotionStrategy halfOffPromo = new HalfOffPromotionStrategy();
PromotionStrategy clearancePromo = new ClearancePromotionStrategy();
Customer customer1 = new Customer(halfOffPromo);
customer1.addItem(100.0);
customer1.addItem(50.0);
customer1.addItem(20.0);
System.out.println("Customer 1");
System.out.println("Total: " + customer1.getTotalBeforePromo());
System.out.println("Total (After Promo): " + customer1.getTotalAfterPromo());
Customer customer2 = new Customer(clearancePromo);
customer2.addItem(100.0);
customer2.addItem(50.0);
customer2.addItem(20.0);
System.out.println("Customer 2");
System.out.println("Total: " + customer2.getTotalBeforePromo());
System.out.println("Total (After Promo):" + customer2.getTotalAfterPromo());
}
}
class Customer {
private List<Double> items;
private PromotionStrategy promotionStrategy;
public Customer(PromotionStrategy promotionStrategy) {
this.promotionStrategy = promotionStrategy;
this.items = Lists.newArrayList();
}
public void addItem(Double item){
items.add(item);
}
public double getTotalBeforePromo(){
double total = items.stream().mapToDouble(i -> i).sum();
return total;
}
public double getTotalAfterPromo(){
double total = getTotalBeforePromo();
double promotion = promotionStrategy.getPromotion(total);
return total - promotion;
}
}
interface PromotionStrategy{
double getPromotion(Double totalAmount);
}
class HalfOffPromotionStrategy implements PromotionStrategy {
@Override
public double getPromotion(Double totalAmount) {
return totalAmount * 0.5;
}
}
class ClearancePromotionStrategy implements PromotionStrategy{
@Override
public double getPromotion(Double totalAmount) {
return totalAmount * 0.75;
}
}